﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("AnalysisLib")]
namespace ElevatorLib
{
    /// <summary>
    /// 乘客类
    /// The passenger's type
    /// </summary>
    public class Person
    {
        #region Properties
        /// <summary>
        /// 是否上行请求
        /// wheather upward request
        /// </summary>
        internal bool isUp = true;
        /// <summary>
        /// 到达时间
        /// Arrival time
        /// </summary>
        internal double arriveTime = 0.0;
        /// <summary>
        /// 起始楼层
        /// Initial floor
        /// </summary>
        internal int originFloor = 0;

        /// <summary>
        /// 目标楼层
        /// Target floor
        /// </summary>
        internal int targetFloor = -1;
        /// <summary>
        /// 乘客进入轿厢耗时
        /// </summary>
        internal double timeIn = 0.0;
        /// <summary>
        /// 乘客走出轿厢耗时
        /// </summary>
        internal double timeOut = 0.0;
        /// <summary>
        /// 乘客进入轿厢后一段时间后才发出内招请求
        /// </summary>
        internal double requestDelay = 0.0;
        /// <summary>
        /// 乘客内招请求事件
        /// </summary>
        internal InCarRequestEvent inCarRequestEvent;
        /// <summary>
        /// 候梯时间
        /// Waiting time
        /// </summary>
        /// <remarks>（开始服务时间点-请求服务时间点）</remarks>
        /// (Starting service time-Asking for service time)
        internal double waitTime = 0.0;
        /// <summary>
        /// 乘梯时间
        /// Ride ladder time 
        /// </summary>
        /// <remarks>（结束服务时间点-开始服务时间点）</remarks>
        /// (Fininsh service time-Asking for service time)
        internal double servTime = 0.0;
        

        /// <summary>
        /// 到达时间
        /// </summary>
        public double ArriveTime
        {
            get
            {
                return arriveTime;
            }
        }

        /// <summary>
        /// 起始楼层
        /// </summary>
        public int OriginFloor
        {
            get
            {
                return originFloor;
            }
        }
        #endregion

        #region Function
        /// <summary>
        /// 到达电梯厅（申请服务）
        /// Arrive elevator hall(ask for service)
        /// </summary>
        internal void Arrive()
        {
            #region 计算乘客请求是向上还是向下
            if (originFloor - targetFloor < 0)
            {
                isUp = true;
            }
            else
            {
                isUp = false;
            }
            #endregion

            

            #region 判断是否有电梯已经在接收乘客，即电梯在WAIT2CLOSE状态，是否同向，若成立，则该乘客进入该电梯

            foreach (Elevator elevator in Building.elevators)
            {
                if (elevator.state == ElevatorState.WAIT2CLOSE)
                {
                    #region 电梯方向与乘客意向相反是乘客不进入电梯
                    if (this.isUp == false && elevator.runningDirection == ElevatorDirection.UP)
                    {
                        continue;
                    }
                    if (this.isUp == true && elevator.runningDirection == ElevatorDirection.DOWN)
                    {
                        continue;
                    }
                    #endregion

                    #region 满载处理
                    if (elevator.isFull)
                    {
                        continue;
                    }
                    #endregion

                    Building.waitingPeople[this.originFloor].Dequeue();
                    if (Building.waitingPeople[this.originFloor].Count == 0)
                    {
                        Building.waitingPeople.Remove(this.originFloor);
                    }

                    elevator.peopleCount++;
                    if (elevator.peopleCount >= elevator.container)
                    {
                        elevator.isFull = true;    //满载
                    }
                    
                    #region 若已存在内招请求则不发送内招请求
                    if (elevator.peopleInCar.ContainsKey(this.targetFloor))
                    {
                        elevator.peopleInCar[this.targetFloor].Enqueue(this);
                    }
                    else
                    {                       
                        #region 内招事件
                        this.inCarRequestEvent = new InCarRequestEvent(this, elevator);
                        this.inCarRequestEvent.SimTime = SimulationEngine.currentTime + this.requestDelay;
                        SimulationEngine.events.Add(this.inCarRequestEvent);
                        #endregion
                    }
                    #endregion

                    #region 修改电梯事件
                    elevator.elevatorArrivedEvent.SimTime += this.timeIn;
                    #endregion

                    return;
                }
            }

            #endregion

            #region 判断该楼层是否已经有用户发送了相同的请求，如果有则不发送请求如果没有则发送请求
            if (isUp)
            {
                switch (Building.floorRequest[originFloor])
                {
                    case RequestType.DOUBLE:
                        {
                            break;
                        }
                    case RequestType.UP:
                        {
                            break;
                        }
                    case RequestType.DOWN:
                        {
                            Building.floorRequest[originFloor] = RequestType.DOUBLE;
                            SimulationEngine.strategyState = StrategyState.PERSON_UP;
                            Building.AllElevatorsRefresh();
                            SimulationEngine.controlStrategy.Execute(this, null);
                            break;
                        }
                    case RequestType.NULL:
                        {
                            Building.floorRequest[originFloor] = RequestType.UP;
                            SimulationEngine.strategyState = StrategyState.PERSON_UP;
                            Building.AllElevatorsRefresh();
                            SimulationEngine.controlStrategy.Execute(this, null);
                            break;
                        }
                }
            }
            else
            {
                switch (Building.floorRequest[originFloor])
                {
                    case RequestType.DOUBLE:
                        {
                            break;
                        }
                    case RequestType.UP:
                        {
                            Building.floorRequest[originFloor] = RequestType.DOUBLE;
                            SimulationEngine.strategyState = StrategyState.PERSON_DOWN;
                            Building.AllElevatorsRefresh();
                            SimulationEngine.controlStrategy.Execute(this, null);
                            break;
                        }
                    case RequestType.DOWN:
                        {
                            break;
                        }
                    case RequestType.NULL:
                        {
                            Building.floorRequest[originFloor] = RequestType.DOWN;
                            SimulationEngine.strategyState = StrategyState.PERSON_DOWN;
                            Building.AllElevatorsRefresh();
                            SimulationEngine.controlStrategy.Execute(this, null);
                            break;
                        }
                }
            }
            #endregion

        }

        /// <summary>
        /// 进入轿厢（开始服务）
        /// Enter the cab(starting service)
        /// </summary>
        internal void IntoCar()
        {
            //计算顾客等待时间
            //Caculate the waiting time of the passenger
            this.waitTime = SimulationEngine.currentTime - this.arriveTime;
        }

        /// <summary>
        /// 走出轿厢（服务结束）
        /// get out of the cab(service finished)
        /// </summary>
        internal void OutCar()
        {
            //计算顾客乘梯时间
            //Caculate the ride ladder time  of the passenger
            this.servTime = SimulationEngine.currentTime - this.arriveTime - this.waitTime;
        }

        #endregion
    }
}
